package com.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.enums.BizCodeEnum;
import com.enums.ProjectTypeEnum;
import com.exception.BizException;
import com.interceptor.LoginInterceptor;
import com.mapper.*;
import com.model.*;
import com.request.ProjectCreateRequest;
import com.request.ProjectDeleteRequest;
import com.service.ProjectService;
import com.utils.FileMappingUtil;
import com.utils.JsonData;
import com.vo.ProjectVO;
import com.vo.UserVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.io.*;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author rkc
 * @date 2022/8/25 15:40
 */
@Slf4j
@Service
public class ProjectServiceImpl implements ProjectService {

    @Resource
    private LanguageMapper languageMapper;

    @Resource
    private ProjectTemplateMapper projectTemplateMapper;

    @Resource
    private BuildToolMapper buildToolMapper;

    @Resource
    private ProjectMapper projectMapper;

    @Autowired
    private FileMappingUtil fileMappingUtil;

    @Resource
    private UserMapper userMapper;

    /**
     * 创建项目，插入数据库后在服务器创建目录映射
     * @param projectCreateRequest
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
    public JsonData createPro(ProjectCreateRequest projectCreateRequest) {
        //根据传入信息查询是否有对应的创建模板
        QueryWrapper<ProjectTemplateDO> qw = new QueryWrapper<ProjectTemplateDO>().eq("lang_id", projectCreateRequest.getLangId())
                .eq("v_id", projectCreateRequest.getLangVersionId());
        if (projectCreateRequest.getBuildToolId() != null) {
            qw.eq("build_id", projectCreateRequest.getBuildToolId());
        } else {
            //2表示不选择依赖管理工具
            qw.eq("build_id", 2);
        }
        ProjectTemplateDO projectTemplateDO = projectTemplateMapper.selectOne(qw);
        if (projectTemplateDO == null) {
            throw new BizException(BizCodeEnum.NOT_EXIST_TEMPLATE);
        }
        //插入数据库
        ProjectDO projectDO = new ProjectDO();
        projectDO.setCreateTime(new Date());
        projectDO.setProjectName(projectCreateRequest.getProjectName());
        projectDO.setProjectTemplateId(projectTemplateDO.getId());
        projectDO.setUid(LoginInterceptor.THREAD_LOCAL.get().getUid());
        if (projectMapper.insert(projectDO) > 0) {
            File target = new File(fileMappingUtil.mapping(projectCreateRequest.getProjectName()));
            log.info("将在{}下创建模板", target.getAbsolutePath());
            //检查是否有重名的项目，重名抛出异常
            if (target.exists()) {
                throw new BizException(BizCodeEnum.REPEATED_PROJECT_NAME);
            }
            target.mkdirs();
            try {
                //在指定的路径下递归创建模板项目
                createProject(new File(projectTemplateDO.getPath()), target, projectTemplateDO, projectCreateRequest);
                //将创建结果查询返回回去
                return selectProById(projectDO.getId());
            } catch (IOException e) {
                log.error(e.getMessage());
                return JsonData.buildError("创建失败");
            }
        }
        return JsonData.buildError("创建失败");
    }

    /**
     * 拿到websocket的链接
     * 根据项目id查询使用到的模板，通过模板可以得到使用编程语言、依赖管理工具等信息
     * 依赖工具：1->maven、2->未使用依赖管理工具
     * 语言：1->java
     * @param pid
     * @return
     */
    @Override
    public JsonData getWebsocketUrlByProjectId(Integer pid) {
        ProjectTemplateDO projectTemplateDO = projectTemplateMapper.selectOneByProjectId(pid);
        Map<String, Object> res = new HashMap<>(3);
        if (projectTemplateDO.getBuildId() == ProjectTypeEnum.MAVEN.getCode()) {
            res.put("typeId", ProjectTypeEnum.MAVEN.getCode());
            res.put("content", ProjectTypeEnum.MAVEN.getMessage());
            res.put("url", ProjectTypeEnum.MAVEN.getWebsocketUrl());
            return JsonData.buildSuccess(res);
        }
        //2表示未使用依赖管理工具
        if (projectTemplateDO.getBuildId() == 2 && projectTemplateDO.getLangId() == 1) {
            res.put("typeId", ProjectTypeEnum.JAVA.getCode());
            res.put("content", ProjectTypeEnum.JAVA.getMessage());
            res.put("url", ProjectTypeEnum.JAVA.getWebsocketUrl());
            return JsonData.buildSuccess(res);
        }
        //其余暂不支持
        return JsonData.buildError("不支持的项目");
    }

    /**
     * 查询自己所有项目
     * @return
     */
    @Override
    public JsonData selectAll() {
        List<ProjectDO> projectDOList = projectMapper.selectList(new QueryWrapper<ProjectDO>().eq("uid", LoginInterceptor.THREAD_LOCAL.get().getUid())
                .orderByDesc("create_time"));
        List<ProjectVO> projectVOList = projectDOList.stream().map(obj -> {
            ProjectVO projectVO = new ProjectVO();
            BeanUtils.copyProperties(obj, projectVO);
            //查询所有者信息
            UserDO userDO = userMapper.selectById(obj.getUid());
            UserVO userVO = new UserVO();
            BeanUtils.copyProperties(userDO, userVO);
            projectVO.setOwner(userVO);
            return projectVO;
        }).collect(Collectors.toList());
        return JsonData.buildSuccess(projectVOList);
    }

    /**
     * 删除目录
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
    public JsonData deletePro(ProjectDeleteRequest projectDeleteRequest) {
        //如果操作的不是自己的项目，则失败
        LoginUser loginUser = LoginInterceptor.THREAD_LOCAL.get();
        if (!projectDeleteRequest.getUid().equals(loginUser.getUid())) {
            throw new BizException(BizCodeEnum.PERMISSION_DENIED);
        }
        //查询数据库得到最新名字进行删除
        ProjectDO projectDO = projectMapper.selectById(projectDeleteRequest.getId());
        String path = fileMappingUtil.mapping(projectDO.getProjectName());
        deleteDirectory(fileMappingUtil.mapping(path));
        return JsonData.buildSuccess();
    }

    /**
     * 查询所有构建工具
     * @return
     */
    @Override
    public JsonData selectBuildTools() {
        return JsonData.buildSuccess(buildToolMapper.selectList(new QueryWrapper<BuildToolDO>().ne("id", 2)));
    }

    /**
     * 根据id查询项目信息
     * @param pid
     * @return
     */
    @Override
    public JsonData selectProById(Integer pid) {
        ProjectDO projectDO = projectMapper.selectById(pid);
        ProjectVO projectVO = new ProjectVO(projectDO.getId(), null, projectDO.getProjectTemplateId(), projectDO.getProjectName(),
                projectDO.getCreateTime());
        UserDO userDO = userMapper.selectById(projectDO.getUid());
        UserVO userVO = new UserVO();
        BeanUtils.copyProperties(userDO, userVO);
        projectVO.setOwner(userVO);
        return JsonData.buildSuccess(projectVO);
    }

    /**
     * 递归删除项目目录下的所有内容
     * @param dest
     */
    private void deleteDirectory(String dest) {
        File f = new File(dest);
        if (f.isFile()) {
            f.delete();
            return;
        }
        File[] fs = f.listFiles();
        if (fs != null) {
            if (fs.length != 0) {
                for (File fi : fs) {
                    deleteDirectory(fi.getAbsolutePath());
                }
            }
            f.delete();
        }
    }

    /**
     * 递归将模板目录的内容在目标目录下进行创建
     * @param src 模板所在位置
     * @param dest 创建位置
     * @throws IOException
     */
    private void createProject(File src, File dest, ProjectTemplateDO projectTemplateDO, ProjectCreateRequest projectCreateRequest) throws IOException {
        if (src.isFile()) {
            try (
                    BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(src.getAbsolutePath())));
                    BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(dest.getAbsolutePath() + File.separator + src.getName(), true)));
            ) {
                boolean flag = "pom.xml".equals(src.getName()) && projectTemplateDO.getBuildId() == ProjectTypeEnum.MAVEN.getCode();
                //如果是maven项目，需要修改模板里面的坐标信息
                String line = null;
                while ((line = reader.readLine()) != null) {
                    if (flag) {
                        switch (line) {
                            case "    <groupId>org.rkc</groupId>":
                                line = String.format("    <groupId>%s</groupId>", projectCreateRequest.getGroupId());
                                break;
                            case "    <artifactId>maven-template</artifactId>":
                                line = String.format("    <artifactId>%s</artifactId>", projectCreateRequest.getArtifactId());
                                break;
                            case "    <version>1.0-SNAPSHOT</version>":
                                line = String.format("    <version>%s</version>", projectCreateRequest.getVersion());
                                break;
                            default:
                                break;
                        }
                    }
                    writer.write(line);
                    writer.newLine();
                }
            }
            return;
        }
        File[] files = src.listFiles();
        for (File file : files) {
            File temp = dest;
            if (file.isDirectory()) {
                String path = dest.getAbsolutePath() + File.separator + file.getName();
                temp = new File(path);
                temp.mkdir();
            }
            createProject(file, temp, projectTemplateDO, projectCreateRequest);
        }
    }
}
